/****************************************************************************
File:			EDFrame.h
Purpose:		This class allows for the creation of matrix/transform hierarchies.
				Hierarchies consist of multiple EDFrames, each with it's own object/local
				space matrix and it's own global/world space matrix.

				The object/local space matrix (m_LocalMat) stores transformations applied only to this frame.
				The position and orientation of the local space matrix is relative to the postion and orientation of the parent.

				The global/world space matrix (m_WorldMat) stores the concatenation (multiplication) of the local space
				matrix with the parent frame's world space matrix. The position and orientation of the world space matrix
				is in absolute world-space. It is where the object would/could be rendered.

				NOTE:
				The implementation of this class is not an exercise in efficiency. It is designed to achieve the desired
				result in a clear and concise manner and to demonstrate the principle of a matrix/transform hierarchy.
Author:			Matt Norris [mnorris@fullsail.com]
School:			Full Sail University
Last Modified:	July 1st, 2009
*****************************************************************************/

#ifndef _EDFRAME_H_
#define _EDFRAME_H_

#include <vector>
using namespace std;

#include "matrix4.h"

class EDFrame
{
	// The local space matrix of the frame.
	matrix4f m_LocalMat;

	// The world space matrix of the frame.
	matrix4f m_WorldMat;

	// Flags used to identify if the frame needs to be updated
	unsigned int m_uiFlags;

	// Pointer to the frames parent if it has one
	EDFrame *m_pParent;

	// Vector of children frames that this frame is a parent of
	vector< EDFrame * > m_vpChildren;

public:
	// Enumeration of valid flags in m_uiFlags
	enum { DIRTY = 1 };

	// Constructor
	EDFrame(void) : m_uiFlags(0), m_pParent(NULL)
	{
	}

	// Destructor
	virtual ~EDFrame(void){}

	
	/***********************************************************
	Function:		GetParent
	Purpose:		Get a pointer to the frame's parent.
	Out:
					EDFrame * - Pointer to the frame's parent	
	Last Modified:	July 1st, 2009
	*************************************************************/
	EDFrame *GetParent(void){ return m_pParent; }

	/***********************************************************
	Function:		SetParent
	Purpose:		Set the parent of the frame
	In:
					EDFrame *pFrame - Pointer to the frame to set 
					as the parent	
	Last Modified:	July 1st, 2009
	*************************************************************/
	void SetParent( EDFrame *pFrame ){ m_pParent = pFrame; }

	
	/***********************************************************
	Function:		AddChild
	Purpose:		Add a frame to the children list of this frame
	In:
					EDFrame *pFrame - Pointer to the frame to add 
					as a child	
	Last Modified:	July 1st, 2009
	*************************************************************/
	void AddChild( EDFrame *pFrame )
	{
		m_vpChildren.push_back( pFrame );
	}

	/***********************************************************
	Function:		RemoveChild
	Purpose:		Remove a frame from the children list of this 
					frame
	In:
					EDFrame *pFrame - Pointer to the frame to 
					remove from the children list	
	Last Modified:	July 1st, 2009
	*************************************************************/
	EDFrame *RemoveChild( EDFrame *pFrame )
	{
		EDFrame *pTemp = NULL;

		for( unsigned int i = 0; i < m_vpChildren.size(); ++i )
		{
			if( pFrame == m_vpChildren[i] )
			{
				pTemp = m_vpChildren[i];

				m_vpChildren.erase( m_vpChildren.begin() + i );
				break;
			}
		}

		return pTemp;
	}

	/***********************************************************
	Function:		Update
	Purpose:		"Dirties" a frame and it's children.
					The worldspace matrix (m_WorldMat) of "dirty" 
					frame updated and "cleaned" when GetWorldMat()
					is called.	
	Last Modified:	July 1st, 2009
	*************************************************************/
	void Update(void)
	{
		if( (m_uiFlags & DIRTY) == 0 )
		{
			m_uiFlags |= DIRTY;

			for( unsigned int i = 0; i < m_vpChildren.size(); ++i )
				m_vpChildren[i]->Update();
		}
	}

	/***********************************************************
	Function:		GetLocalMat
	Purpose:		Get the local space matrix of the frame.
	Out:
					matrix4f& - The local space matrix of the frame
	Last Modified:	July 1st, 2009
	*************************************************************/
	matrix4f& GetLocalMat(void){ return m_LocalMat; }


	/***********************************************************
	Function:		GetWorldMat
	Purpose:		Get the world space matrix of the frame. If 
					the frame is "dirty", the world space matrix 
					is first recalculated and the frame is 
					cleaned.
	Out:
					const matrix4f& -	The world space matrix of 
					the frame. This is returned as constant, as 
					the world space matrix should not be edited 
					directly. Any changes made directly to the 
					world space matrix will be lost when the 
					matrix is next updated because 
					m_WorldMat = m_LocalMat, or 
					m_WorldMat = m_LocalMat * pParent->m_WorldMat.
	Last Modified:	July 1st, 2009
	*************************************************************/
	const matrix4f& GetWorldMat(void)
	{
		if( (m_uiFlags & DIRTY) != 0 )
		{
			if( m_pParent != NULL )
				 m_WorldMat = m_LocalMat * m_pParent->GetWorldMat();
			else
				m_WorldMat = m_LocalMat;

			m_uiFlags &= ~DIRTY;
		}

		return m_WorldMat;
	}
};

#endif